
#include "aliyun_iot_platform_network.h"
#include "aliyun_iot_common_log.h"
#include "aliyun_iot_mqtt_nettype.h"
#include "aliyun_iot_platform_uart.h"
#include "aliyun_iot_platform_pthread.h"
#include "xrj_protocol.h"
typedef struct
{
	UINT32 size;
	UINT32 head;
	UINT32 tail;
	UINT8 *buffer;
} iot_ring_buffer_t;

#define MQTT_RING_BUFFER_LEN MSG_SIZE_RX

static iot_ring_buffer_t  mqtt_ring_buffer;
static UINT8 mqtt_ring_data[MQTT_RING_BUFFER_LEN] = {0};
INT32 g_SEND_timeOutMs;
INT32 f_SEND_timeOutMs;

INT32 g_RECV_timeOutMs;
INT32 f_RECV_timeOutMs;

#define IOT_MIN(x,y)  ((x) < (y) ? (x) : (y))

/*
	Initializes the size of the ring buffer
*/
INT32 aliyun_iot_ring_buffer_init( iot_ring_buffer_t *ring_buffer, UINT8 *buffer, UINT32 size )
{
    ring_buffer->buffer     = buffer;
    ring_buffer->size       = size;
    ring_buffer->head       = 0;
    ring_buffer->tail       = 0;
    return 0;
}

/*
	the size of ring buffer is already in use
*/
UINT32 aliyun_iot_ring_buffer_used_space( iot_ring_buffer_t *ring_buffer )
{
	UINT32 head_to_end = ring_buffer->size - ring_buffer->head;
	return ((head_to_end + ring_buffer->tail) % ring_buffer->size);
}


/*
	read mqtt data from ring buffer
*/
UINT8 aliyun_iot_ring_buffer_read(iot_ring_buffer_t *ring_buffer, UINT8 *data, UINT32 bytes_consume)
{
	UINT32 head_to_end = ring_buffer->size - ring_buffer->head;
	if(bytes_consume < head_to_end)
	{
		memcpy(data, &(ring_buffer->buffer[ring_buffer->head]), bytes_consume);
	}
	else
	{
		memcpy(data, &(ring_buffer->buffer[ring_buffer->head]), head_to_end);
		memcpy((data + head_to_end), ring_buffer->buffer, (bytes_consume - head_to_end));
	}
	ring_buffer->head = (ring_buffer->head + bytes_consume) % ring_buffer->size;
	return 0;
}

/*
	store mqtt data into global ring buffer
*/
UINT32 aliyun_iot_ring_buffer_write( iot_ring_buffer_t *ring_buffer, const UINT8 *data, UINT32 data_length )
{
	UINT32 tail_to_end = ring_buffer->size - ring_buffer->tail;

	/* Calculate the maximum amount we can copy */
	UINT32 amount_to_copy = IOT_MIN(data_length, (ring_buffer->tail == ring_buffer->head) ? ring_buffer->size : (tail_to_end + ring_buffer->head) % ring_buffer->size);

	/* Copy as much as we can until we fall off the end of the buffer */
	memcpy(&ring_buffer->buffer[ring_buffer->tail], data, IOT_MIN(amount_to_copy, tail_to_end));

	/* Check if we have more to copy to the front of the buffer */
	if (tail_to_end < amount_to_copy)
	{
		memcpy(ring_buffer->buffer, data + tail_to_end, amount_to_copy - tail_to_end);
	}

	/* Update the tail */
	ring_buffer->tail = (ring_buffer->tail + amount_to_copy) % ring_buffer->size;

	return amount_to_copy;
}







INT32 aliyun_iot_get_errno(void)
{
    return EAGAIN_IOT;
}

INT32 aliyun_iot_network_send(INT32 sockFd, void *buf, INT32 nbytes, UINT32 flags)
{
	
	if(!buf)
	{	
		return -1;
	}
//	IWDG_Feed();
	aliyun_iot_uart_send((char *)buf,nbytes);
	
	return nbytes;	
	
}



INT8  uartMsg[MQTT_RING_BUFFER_LEN] = {0};
INT32 aliyun_iot_network_recv(INT32 sockFd, void *pRecvBuffer, INT32 recvBufferlen, UINT32 flags)
{
	
		INT32 readLen = 0;
		INT32 msgLen = 0;

		IWDG_Feed();
		if(!recvBufferlen)
		{
				WRITE_IOT_ERROR_LOG("param error, recvbuffer is null");
				return -1;
		}
//		WRITE_IOT_DEBUG_LOG("mqtt_read: recvBufLen=%d timeout=%d", recvBufferlen, g_RECV_timeOutMs);
	
	
	
		INT32 dataLen = aliyun_iot_ring_buffer_used_space(&mqtt_ring_buffer);
		if(dataLen)
		{
	
			// read mqtt data from ringbuffer
				readLen = (dataLen > recvBufferlen) ? recvBufferlen : dataLen;
				aliyun_iot_ring_buffer_read(&mqtt_ring_buffer, pRecvBuffer, readLen);
			
				WRITE_IOT_DEBUG_LOG("mqtt_read1: recvBufLen=%d msgLen = %d timeout=%d", recvBufferlen,readLen, g_RECV_timeOutMs);
				
				return readLen;
		}
		else
		{
//				int i;
				memset(uartMsg,0,MQTT_RING_BUFFER_LEN);
				msgLen = aliyun_iot_uart_recv((char *)uartMsg, recvBufferlen, g_RECV_timeOutMs);
						
				if (msgLen > 0)
				{	
					WRITE_IOT_DEBUG_LOG("mqtt_read2: recvBufLen=%d msgLen = %d timeout=%d\n", recvBufferlen,msgLen, g_RECV_timeOutMs);
					aliyun_iot_ring_buffer_write(&mqtt_ring_buffer, (unsigned char*)uartMsg, msgLen);
					readLen = (msgLen > recvBufferlen) ? recvBufferlen : msgLen;
					aliyun_iot_ring_buffer_read(&mqtt_ring_buffer, pRecvBuffer, readLen);
				}
				else if (msgLen == 0)
				{
					readLen = 0;
				}	
				else if (msgLen == -2)
				{
					readLen = -2;
				}	
				else
				{
					readLen = -1;
				}	
				return readLen;			
		}	
		
}

INT32 aliyun_iot_network_select(INT32 fd,IOT_NET_TRANS_TYPE_E type,int timeoutMs,IOT_NET_FD_ISSET_E* result)
{
		if (type ==IOT_NET_TRANS_SEND)	
		{	
				g_SEND_timeOutMs = timeoutMs;
				f_SEND_timeOutMs = 1;
		}		
		else
		{	
				g_RECV_timeOutMs = timeoutMs;
				f_RECV_timeOutMs = 1;
		}
	return 2;
}

INT32 aliyun_iot_network_settimeout(INT32 fd,int timeoutMs,IOT_NET_TRANS_TYPE_E type)
{
		if (type ==IOT_NET_TRANS_SEND)
		{		
				if (f_SEND_timeOutMs == 1)	
						g_SEND_timeOutMs += timeoutMs;
				else
						g_SEND_timeOutMs = timeoutMs;
				f_SEND_timeOutMs = 0;
				
		}
		else
		{	
				if (f_RECV_timeOutMs == 1)	
						g_RECV_timeOutMs += timeoutMs;
				else
						g_RECV_timeOutMs = timeoutMs;
				f_RECV_timeOutMs = 0;
		}
		return 0;
}

INT32 aliyun_iot_network_get_nonblock(INT32 fd)
{
	return 0;
}

INT32 aliyun_iot_network_set_nonblock(INT32 fd)
{
	return 0;
}

INT32 aliyun_iot_network_set_block(INT32 fd)
{
	return 0;
}

INT32 aliyun_iot_network_close(INT32 fd)
{
	aliyun_iot_uart_Close_TCP(fd);
	return 0;	
}

INT32 aliyun_iot_network_shutdown(INT32 fd,INT32 how)
{
    return 0;
}

INT32 aliyun_iot_network_create( INT8*host, INT8*service,IOT_NET_PROTOCOL_TYPE type)
{	
	
	//mqtt ring buffer init
	aliyun_iot_ring_buffer_init(&mqtt_ring_buffer, (UINT8 *)mqtt_ring_data, MQTT_RING_BUFFER_LEN);
	return aliyun_iot_uart_Open_TCP(host, service, type);	
	
}

INT32 aliyun_iot_network_bind(const INT8*host,const INT8*service,IOT_NET_PROTOCOL_TYPE type)
{
	return 0;
}


